import { BoolItem, Operator, Expression, BoolOperation } from './types';
import { isBoolExpression } from './util';
import {sortBy} from 'lodash';

function printBoolItem(exp: BoolItem): string {
  const { key, value } = exp;
  let left = 0;
  let right = 0;

  if (Array.isArray(value) && value.length > 1) {
    [left, right] = value as number[];
  }

  switch (exp.operator) {
    case Operator.FULL:
      return 'FULL';
    case Operator.EMPTY:
      return 'EMPTY';
    case Operator.EQ:
      return `${key} == ${value}`;
    case Operator.NEQ:
      return `${key} != ${value}`;
    case Operator.IN:
      return `${key} in ${JSON.stringify(sortBy(value as number[])).replace(/,/g, ', ')}`;
    case Operator.NOT_IN:
      return `${key} not in ${JSON.stringify(sortBy(value as number[])).replace(/,/g, ', ')}`;
    case Operator.LT:
      return `${key} < ${value}`;
    case Operator.GT:
      return `${key} > ${value}`;
    case Operator.NGT:
      return `${key} <= ${value}`;
    case Operator.NLT:
      return `${key} >= ${value}`;
    case Operator.RIN:
      return `${key} ~ [${left}, ${right}]`;
    case Operator.LO_IN_INNER:
      return `${key} ~ (${left}, ${right}]`;
    case Operator.RO_IN_INNER:
      return `${key} ~ [${left}, ${right})`;
    case Operator.O_IN_INNER:
      return `${key} ~ (${left}, ${right})`;
    case Operator.SEGMENTS_INNER:
      return (exp.value as BoolItem[]).map(printBoolItem).join(' || ');
    default:
      throw new Error(`Invalid Operator ${exp.operator}`);
  }
}

/**
 * 打印一堆 && 关系的布尔项
 *
 * @param {BoolItem[]} list - 布尔项
 * @return {string} 可读的字符串
 */
export function printBoolItemList(list: BoolItem[]): string {
  if (list.length === 1) {
    return printBoolItem(list[0]);
  }
  return list.map((item: BoolItem) => `(${printBoolItem(item)})`).join(' && ');
}

/**
 * 打印表达式
 *
 * @param {Expression} exp - 表达式
 * @return {string} 字符串格式， 空字符串表示全集，null表示空集
 */
export function print(exp: Expression): string {
  if (isBoolExpression(exp)) {
    const op = exp.operator === BoolOperation.AND ? ' && ' : ' || ';
    return exp.args.map((item: Expression) => `(${print(item)})`).join(op);
  } else {
    return printBoolItem(exp);
  }
}
